package cn.monkey.family.server.domain.sys.address;

import cn.monkey.family.data.Result;
import cn.monkey.family.data.Results;
import cn.monkey.family.data.context.RequestContext;
import cn.monkey.family.data.crud.AbstractCrudService;
import cn.monkey.family.data.sys.address.*;
import cn.monkey.family.server.domain.sys.file.IFileHandler;
import com.opencsv.CSVReader;
import com.opencsv.CSVWriter;
import com.opencsv.bean.CsvToBean;
import com.opencsv.bean.CsvToBeanBuilder;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Collection;
import java.util.List;

@Service
public class AddressService extends AbstractCrudService<String, AddressQueryRequest, Address, AddressDto, AddressVo, AddressMapper, AddressRepository>
        implements IAddressService, IFileHandler {

    public AddressService(AddressRepository repository, AddressMapper mapper) {
        super(repository, mapper);
    }


    @Override
    public Result<Collection<AddressTree>> readTree(RequestContext requestContext, AddressQueryRequest queryRequest) {
        Result<Collection<AddressVo>> result = this.readAll(requestContext, queryRequest, Sort.unsorted());
        if (!Results.isOk(result)) {
            return Results.fromFailOrError(result);
        }
        return Results.ok(this.mapper.toTree(result.getData()));
    }

    @Override
    public String getName() {
        return "address";
    }


    @Override
    public void download(RequestContext requestContext,
                         HttpServletRequest request,
                         HttpServletResponse response) throws IOException {
        AddressQueryRequest queryRequest = AddressQueryRequests.fromHttpServletRequest(request);
        int pageIndex = 0;
        int pageSize = 1000;
        Page<AddressVo> page;
        try (CSVWriter csvWriter = new CSVWriter(new OutputStreamWriter(response.getOutputStream()))) {
            csvWriter.writeNext(new String[]{"provinceCode", "provinceName", "cityCode", "cityName", "countryCode", "countryName", "streetCode", "streetName"});
            response.addHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=address.csv");
            do {
                Result<Page<AddressVo>> pageResult = this.readPage(requestContext, queryRequest, PageRequest.of(pageIndex, pageSize));
                if (!Results.isOk(pageResult)) {
                    break;
                }
                page = pageResult.getData();
                csvWriter.writeAll(page.getContent().stream().map(this.mapper::toStrLine).toList());
                csvWriter.flush();
                pageIndex++;
            } while (page.hasNext());
        }
    }

    protected List<Address> fromFile(MultipartFile file) throws IOException {
        try (CSVReader reader = new CSVReader(new InputStreamReader(file.getInputStream()))) {
            AddressMappingStrategy mappingStrategy = new AddressMappingStrategy();
            CsvToBean<Address> csvToBean = new CsvToBeanBuilder<Address>(reader)
                    .withSkipLines(1)
                    .withMappingStrategy(mappingStrategy)
                    .build();
            return csvToBean.parse();
        }
    }


    @Override
    public Result<?> upload(RequestContext requestContext, MultipartHttpServletRequest request) throws IOException {
        for (MultipartFile file : request.getFileMap().values()) {
            List<Address> addresses = this.fromFile(file);
            this.repository.saveAll(addresses);
        }
        return Results.ok();
    }
}
